home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / file-tra / ftp-rl.taz / ftp-rl / ftp / glob.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-07  |  10.2 KB  |  664 lines

  1. #define NCARGS 0x10000
  2. /*
  3.  * Copyright (c) 1980 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted
  7.  * provided that: (1) source distributions retain this entire copyright
  8.  * notice and comment, and (2) distributions including binaries display
  9.  * the following acknowledgement:  ``This product includes software
  10.  * developed by the University of California, Berkeley and its contributors''
  11.  * in the documentation or other materials provided with the distribution
  12.  * and in all advertising materials mentioning features or use of this
  13.  * software. Neither the name of the University nor the names of its
  14.  * contributors may be used to endorse or promote products derived
  15.  * from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. static char sccsid[] = "@(#)glob.c    5.8 (Berkeley) 6/1/90";
  23. #endif /* not lint */
  24.  
  25. /*
  26.  * C-shell glob for random programs.
  27.  */
  28.  
  29. #include <sys/param.h>
  30. #include <sys/stat.h>
  31. #include <sys/dir.h>
  32.  
  33. #include <stdio.h>
  34. #include <errno.h>
  35. #include <pwd.h>
  36.  
  37. #define    QUOTE 0200
  38. #define    TRIM 0177
  39. #define    eq(a,b)        (strcmp(a, b)==0)
  40. #define    GAVSIZ        (NCARGS/6)
  41. #define    isdir(d)    ((d.st_mode & S_IFMT) == S_IFDIR)
  42.  
  43. static    char **gargv;        /* Pointer to the (stack) arglist */
  44. static    int gargc;        /* Number args in gargv */
  45. static    int gnleft;
  46. static    short gflag;
  47. static    int tglob();
  48. char    **glob();
  49. char    *globerr;
  50. char    *home;
  51. struct    passwd *getpwnam();
  52. extern    int errno;
  53. static    char *strspl(), *strend();
  54. char    *malloc(), *strcpy(), *strcat();
  55. char    **copyblk();
  56.  
  57. static    int globcnt;
  58.  
  59. char    *globchars = "`{[*?";
  60.  
  61. static    char *gpath, *gpathp, *lastgpathp;
  62. static    int globbed;
  63. static    char *entp;
  64. static    char **sortbas;
  65.  
  66. char **
  67. glob(v)
  68.     register char *v;
  69. {
  70.     char agpath[BUFSIZ];
  71.     char *agargv[GAVSIZ];
  72.     char *vv[2];
  73.     vv[0] = v;
  74.     vv[1] = 0;
  75.     gflag = 0;
  76.     rscan(vv, tglob);
  77.     if (gflag == 0)
  78.         return (copyblk(vv));
  79.  
  80.     globerr = 0;
  81.     gpath = agpath; gpathp = gpath; *gpathp = 0;
  82.     lastgpathp = &gpath[sizeof agpath - 2];
  83.     ginit(agargv); globcnt = 0;
  84.     collect(v);
  85.     if (globcnt == 0 && (gflag&1)) {
  86.         blkfree(gargv), gargv = 0;
  87.         return (0);
  88.     } else
  89.         return (gargv = copyblk(gargv));
  90. }
  91.  
  92. static
  93. ginit(agargv)
  94.     char **agargv;
  95. {
  96.  
  97.     agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
  98.     gnleft = NCARGS - 4;
  99. }
  100.  
  101. static
  102. collect(as)
  103.     register char *as;
  104. {
  105.     if (eq(as, "{") || eq(as, "{}")) {
  106.         Gcat(as, "");
  107.         sort();
  108.     } else
  109.         acollect(as);
  110. }
  111.  
  112. static
  113. acollect(as)
  114.     register char *as;
  115. {
  116.     register int ogargc = gargc;
  117.  
  118.     gpathp = gpath; *gpathp = 0; globbed = 0;
  119.     expand(as);
  120.     if (gargc != ogargc)
  121.         sort();
  122. }
  123.  
  124. static
  125. sort()
  126. {
  127.     register char **p1, **p2, *c;
  128.     char **Gvp = &gargv[gargc];
  129.  
  130.     p1 = sortbas;
  131.     while (p1 < Gvp-1) {
  132.         p2 = p1;
  133.         while (++p2 < Gvp)
  134.             if (strcmp(*p1, *p2) > 0)
  135.                 c = *p1, *p1 = *p2, *p2 = c;
  136.         p1++;
  137.     }
  138.     sortbas = Gvp;
  139. }
  140.  
  141. static
  142. expand(as)
  143.     char *as;
  144. {
  145.     register char *cs;
  146.     register char *sgpathp, *oldcs;
  147.     struct stat stb;
  148.  
  149.     sgpathp = gpathp;
  150.     cs = as;
  151.     if (*cs == '~' && gpathp == gpath) {
  152.         addpath('~');
  153.         for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
  154.             addpath(*cs++);
  155.         if (!*cs || *cs == '/') {
  156.             if (gpathp != gpath + 1) {
  157.                 *gpathp = 0;
  158.                 if (gethdir(gpath + 1))
  159.                     globerr = "Unknown user name after ~";
  160.                 (void) strcpy(gpath, gpath + 1);
  161.             } else
  162.                 (void) strcpy(gpath, home);
  163.             gpathp = strend(gpath);
  164.         }
  165.     }
  166.     while (!any(*cs, globchars)) {
  167.         if (*cs == 0) {
  168.             if (!globbed)
  169.                 Gcat(gpath, "");
  170.             else if (stat(gpath, &stb) >= 0) {
  171.                 Gcat(gpath, "");
  172.                 globcnt++;
  173.             }
  174.             goto endit;
  175.         }
  176.         addpath(*cs++);
  177.     }
  178.     oldcs = cs;
  179.     while (cs > as && *cs != '/')
  180.         cs--, gpathp--;
  181.     if (*cs == '/')
  182.         cs++, gpathp++;
  183.     *gpathp = 0;
  184.     if (*oldcs == '{') {
  185.         (void) execbrc(cs, ((char *)0));
  186.         return;
  187.     }
  188.     matchdir(cs);
  189. endit:
  190.     gpathp = sgpathp;
  191.     *gpathp = 0;
  192. }
  193.  
  194. static
  195. matchdir(pattern)
  196.     char *pattern;
  197. {
  198.     struct stat stb;
  199.     register struct direct *dp;
  200.     DIR *dirp;
  201.  
  202.     dirp = opendir(gpath);
  203.     if (dirp == NULL) {
  204.         if (globbed)
  205.             return;
  206.         goto patherr2;
  207.     }
  208.     if (fstat(dirp->dd_fd, &stb) < 0)
  209.         goto patherr1;
  210.     if (!isdir(stb)) {
  211.         errno = ENOTDIR;
  212.         goto patherr1;
  213.     }
  214.     while ((dp = readdir(dirp)) != NULL) {
  215.         if (dp->d_ino == 0)
  216.             continue;
  217.         if (match(dp->d_name, pattern)) {
  218.             Gcat(gpath, dp->d_name);
  219.             globcnt++;
  220.         }
  221.     }
  222.     closedir(dirp);
  223.     return;
  224.  
  225. patherr1:
  226.     closedir(dirp);
  227. patherr2:
  228.     globerr = "Bad directory components";
  229. }
  230.  
  231. static
  232. execbrc(p, s)
  233.     char *p, *s;
  234. {
  235.     char restbuf[BUFSIZ + 2];
  236.     register char *pe, *pm, *pl;
  237.     int brclev = 0;
  238.     char *lm, savec, *sgpathp;
  239.  
  240.     for (lm = restbuf; *p != '{'; *lm++ = *p++)
  241.         continue;
  242.     for (pe = ++p; *pe; pe++)
  243.     switch (*pe) {
  244.  
  245.     case '{':
  246.         brclev++;
  247.         continue;
  248.  
  249.     case '}':
  250.         if (brclev == 0)
  251.             goto pend;
  252.         brclev--;
  253.         continue;
  254.  
  255.     case '[':
  256.         for (pe++; *pe && *pe != ']'; pe++)
  257.             continue;
  258.         continue;
  259.     }
  260. pend:
  261.     brclev = 0;
  262.     for (pl = pm = p; pm <= pe; pm++)
  263.     switch (*pm & (QUOTE|TRIM)) {
  264.  
  265.     case '{':
  266.         brclev++;
  267.         continue;
  268.  
  269.     case '}':
  270.         if (brclev) {
  271.             brclev--;
  272.             continue;
  273.         }
  274.         goto doit;
  275.  
  276.     case ','|QUOTE:
  277.     case ',':
  278.         if (brclev)
  279.             continue;
  280. doit:
  281.         savec = *pm;
  282.         *pm = 0;
  283.         (void) strcpy(lm, pl);
  284.         (void) strcat(restbuf, pe + 1);
  285.         *pm = savec;
  286.         if (s == 0) {
  287.             sgpathp = gpathp;
  288.             expand(restbuf);
  289.             gpathp = sgpathp;
  290.             *gpathp = 0;
  291.         } else if (amatch(s, restbuf))
  292.             return (1);
  293.         sort();
  294.         pl = pm + 1;
  295.         if (brclev)
  296.             return (0);
  297.         continue;
  298.  
  299.     case '[':
  300.         for (pm++; *pm && *pm != ']'; pm++)
  301.             continue;
  302.         if (!*pm)
  303.             pm--;
  304.         continue;
  305.     }
  306.     if (brclev)
  307.         goto doit;
  308.     return (0);
  309. }
  310.  
  311. static
  312. match(s, p)
  313.     char *s, *p;
  314. {
  315.     register int c;
  316.     register char *sentp;
  317.     char sglobbed = globbed;
  318.  
  319.     if (*s == '.' && *p != '.')
  320.         return (0);
  321.     sentp = entp;
  322.     entp = s;
  323.     c = amatch(s, p);
  324.     entp = sentp;
  325.     globbed = sglobbed;
  326.     return (c);
  327. }
  328.  
  329. static
  330. amatch(s, p)
  331.     register char *s, *p;
  332. {
  333.     register int scc;
  334.     int ok, lc;
  335.     char *sgpathp;
  336.     struct stat stb;
  337.     int c, cc;
  338.  
  339.     globbed = 1;
  340.     for (;;) {
  341.         scc = *s++ & TRIM;
  342.         switch (c = *p++) {
  343.  
  344.         case '{':
  345.             return (execbrc(p - 1, s - 1));
  346.  
  347.         case '[':
  348.             ok = 0;
  349.             lc = 077777;
  350.             while (cc = *p++) {
  351.                 if (cc == ']') {
  352.                     if (ok)
  353.                         break;
  354.                     return (0);
  355.                 }
  356.                 if (cc == '-') {
  357.                     if (lc <= scc && scc <= *p++)
  358.                         ok++;
  359.                 } else
  360.                     if (scc == (lc = cc))
  361.                         ok++;
  362.             }
  363.             if (cc == 0)
  364.                 if (ok)
  365.                     p--;
  366.                 else
  367.                     return 0;
  368.             continue;
  369.  
  370.         case '*':
  371.             if (!*p)
  372.                 return (1);
  373.             if (*p == '/') {
  374.                 p++;
  375.                 goto slash;
  376.             }
  377.             s--;
  378.             do {
  379.                 if (amatch(s, p))
  380.                     return (1);
  381.             } while (*s++);
  382.             return (0);
  383.  
  384.         case 0:
  385.             return (scc == 0);
  386.  
  387.         default:
  388.             if (c != scc)
  389.                 return (0);
  390.             continue;
  391.  
  392.         case '?':
  393.             if (scc == 0)
  394.                 return (0);
  395.             continue;
  396.  
  397.         case '/':
  398.             if (scc)
  399.                 return (0);
  400. slash:
  401.             s = entp;
  402.             sgpathp = gpathp;
  403.             while (*s)
  404.                 addpath(*s++);
  405.             addpath('/');
  406.             if (stat(gpath, &stb) == 0 && isdir(stb))
  407.                 if (*p == 0) {
  408.                     Gcat(gpath, "");
  409.                     globcnt++;
  410.                 } else
  411.                     expand(p);
  412.             gpathp = sgpathp;
  413.             *gpathp = 0;
  414.             return (0);
  415.         }
  416.     }
  417. }
  418.  
  419. static
  420. Gmatch(s, p)
  421.     register char *s, *p;
  422. {
  423.     register int scc;
  424.     int ok, lc;
  425.     int c, cc;
  426.  
  427.     for (;;) {
  428.         scc = *s++ & TRIM;
  429.         switch (c = *p++) {
  430.  
  431.         case '[':
  432.             ok = 0;
  433.             lc = 077777;
  434.             while (cc = *p++) {
  435.                 if (cc == ']') {
  436.                     if (ok)
  437.                         break;
  438.                     return (0);
  439.                 }
  440.                 if (cc == '-') {
  441.                     if (lc <= scc && scc <= *p++)
  442.                         ok++;
  443.                 } else
  444.                     if (scc == (lc = cc))
  445.                         ok++;
  446.             }
  447.             if (cc == 0)
  448.                 if (ok)
  449.                     p--;
  450.                 else
  451.                     return 0;
  452.             continue;
  453.  
  454.         case '*':
  455.             if (!*p)
  456.                 return (1);
  457.             for (s--; *s; s++)
  458.                 if (Gmatch(s, p))
  459.                     return (1);
  460.             return (0);
  461.  
  462.         case 0:
  463.             return (scc == 0);
  464.  
  465.         default:
  466.             if ((c & TRIM) != scc)
  467.                 return (0);
  468.             continue;
  469.  
  470.         case '?':
  471.             if (scc == 0)
  472.                 return (0);
  473.             continue;
  474.  
  475.         }
  476.     }
  477. }
  478.  
  479. static
  480. Gcat(s1, s2)
  481.     register char *s1, *s2;
  482. {
  483.     register int len = strlen(s1) + strlen(s2) + 1;
  484.  
  485.     if (len >= gnleft || gargc >= GAVSIZ - 1)
  486.         globerr = "Arguments too long";
  487.     else {
  488.         gargc++;
  489.         gnleft -= len;
  490.         gargv[gargc] = 0;
  491.         gargv[gargc - 1] = strspl(s1, s2);
  492.     }
  493. }
  494.  
  495. static
  496. addpath(c)
  497.     char c;
  498. {
  499.  
  500.     if (gpathp >= lastgpathp)
  501.         globerr = "Pathname too long";
  502.     else {
  503.         *gpathp++ = c;
  504.         *gpathp = 0;
  505.     }
  506. }
  507.  
  508. static
  509. rscan(t, f)
  510.     register char **t;
  511.     int (*f)();
  512. {
  513.     register char *p, c;
  514.  
  515.     while (p = *t++) {
  516.         if (f == tglob)
  517.             if (*p == '~')
  518.                 gflag |= 2;
  519.             else if (eq(p, "{") || eq(p, "{}"))
  520.                 continue;
  521.         while (c = *p++)
  522.             (*f)(c);
  523.     }
  524. }
  525. /*
  526. static
  527. scan(t, f)
  528.     register char **t;
  529.     int (*f)();
  530. {
  531.     register char *p, c;
  532.  
  533.     while (p = *t++)
  534.         while (c = *p)
  535.             *p++ = (*f)(c);
  536. } */
  537.  
  538. static
  539. tglob(c)
  540.     register char c;
  541. {
  542.  
  543.     if (any(c, globchars))
  544.         gflag |= c == '{' ? 2 : 1;
  545.     return (c);
  546. }
  547. /*
  548. static
  549. trim(c)
  550.     char c;
  551. {
  552.  
  553.     return (c & TRIM);
  554. } */
  555.  
  556.  
  557. letter(c)
  558.     register char c;
  559. {
  560.  
  561.     return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_');
  562. }
  563.  
  564. digit(c)
  565.     register char c;
  566. {
  567.  
  568.     return (c >= '0' && c <= '9');
  569. }
  570.  
  571. any(c, s)
  572.     register int c;
  573.     register char *s;
  574. {
  575.  
  576.     while (*s)
  577.         if (*s++ == c)
  578.             return(1);
  579.     return(0);
  580. }
  581. blklen(av)
  582.     register char **av;
  583. {
  584.     register int i = 0;
  585.  
  586.     while (*av++)
  587.         i++;
  588.     return (i);
  589. }
  590.  
  591. char **
  592. blkcpy(oav, bv)
  593.     char **oav;
  594.     register char **bv;
  595. {
  596.     register char **av = oav;
  597.  
  598.     while (*av++ = *bv++)
  599.         continue;
  600.     return (oav);
  601. }
  602.  
  603. blkfree(av0)
  604.     char **av0;
  605. {
  606.     register char **av = av0;
  607.  
  608.     while (*av)
  609.         free(*av++);
  610. }
  611.  
  612. static
  613. char *
  614. strspl(cp, dp)
  615.     register char *cp, *dp;
  616. {
  617.     register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
  618.  
  619.     if (ep == (char *)0)
  620.         fatal("Out of memory");
  621.     (void) strcpy(ep, cp);
  622.     (void) strcat(ep, dp);
  623.     return (ep);
  624. }
  625.  
  626. char **
  627. copyblk(v)
  628.     register char **v;
  629. {
  630.     register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
  631.                         sizeof(char **)));
  632.     if (nv == (char **)0)
  633.         fatal("Out of memory");
  634.  
  635.     return (blkcpy(nv, v));
  636. }
  637.  
  638. static
  639. char *
  640. strend(cp)
  641.     register char *cp;
  642. {
  643.  
  644.     while (*cp)
  645.         cp++;
  646.     return (cp);
  647. }
  648. /*
  649.  * Extract a home directory from the password file
  650.  * The argument points to a buffer where the name of the
  651.  * user whose home directory is sought is currently.
  652.  * We write the home directory of the user back there.
  653.  */
  654. gethdir(home)
  655.     char *home;
  656. {
  657.     register struct passwd *pp = getpwnam(home);
  658.  
  659.     if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
  660.         return (1);
  661.     (void) strcpy(home, pp->pw_dir);
  662.     return (0);
  663. }
  664.